<?php

declare(strict_types=1);

namespace app\model;

use PDOException;
use think\Model;
use think\facade\Db;
use think\exception\ValidateException;
use app\validate\admin\AuthAdminsValidate;
use app\eslib\EsUtils;
use think\helper\Str;

/**
 * 管理员 模型类
 * @version 1.0.0
 */
class AuthAdminsModel extends Model
{
    // 数据表名称常量
    const TABLE_NAME = 'sw_auth_admins';

    // 设置当前模型对应的完整数据表名称
    protected $table = self::TABLE_NAME;

    // 开启自动时间戳（默认为整型int）
    protected $autoWriteTimestamp = true;

    // 定义时间戳字段名
    protected $createTime = 'created_at';
    protected $updateTime = 'updated_at';
    protected $readonly = ['created_at', 'updated_at'];
    /**
     * 设置字段信息
     * 默认会自动获取字段信息（包括字段类型），但会导致增加一次查询，显式在模型中定义字段信息可以避免多一次查询的开销
     * 字段类型的定义可以使用PHP类型或者数据库的字段类型，时间字段尽量采用实际的数据库类型定义，便于时间查询的字段自动识别。如果是json类型直接定义为json即可。
     * 如果你没有定义schema属性的话，可以在部署完成后运行如下指令。php think optimize:schema。运行后会自动生成数据表的字段信息缓存。使用命令行缓存的优势是Db类的查询仍然有效。需要在数据库配置中设置fields_cache为true才能生成缓存
     */
    protected $schema = [
        'id'          => 'int',
        'name'        => 'string',
        'status'      => 'tinyint',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];
    /**
     * 返回 性别 访问器的枚举数据
     */
    public $gender_data = [0 => '未知', 1 => '男', 2 => '女'];

    /**
     * 返回 性别 访问器的值
     */
    public function getGenderTextAttr()
    {
        $value = $this->getData('gender');
        if (is_numeric($value)) {
            $value = intval($value);
        }
        return $this->gender_data[$value] ?? $value;
    }

    /**
     * 返回 状态 访问器的枚举数据
     */
    public $status_data = [0 => '禁用', 1 => '正常'];

    /**
     * 返回 状态 访问器的值
     */
    public function getStatusTextAttr()
    {
        $value = $this->getData('status');
        if (is_numeric($value)) {
            $value = intval($value);
        }
        return $this->status_data[$value] ?? $value;
    }

    /**
     * 使用视图查询
     */
    public function scopeDbView($query)
    {
        return $query->table('v_auth_admins');
    }

    /**
     * 复制指定的记录
     */
    public static function doCopy($id)
    {
        $data = Db::table(self::TABLE_NAME)->where('id', $id)->toArray();
        $data['user_name'] .= ' - 副本';
        unset($data['id']);
        unset($data['created_at']);
        unset($data['updated_at']);
        try {
            $id = Db::table(self::TABLE_NAME)->insertGetId($data);
            return EsUtils::stdMessage(true, '', $id);
        } catch (PDOException $ex) {
            return EsUtils::stdMessage(false, $ex->getMessage());
        }
    }

    /**
     * 显示资源列表
     */
    static public function doIndex($searchText, $pageSize)
    {
        $data = self::dbView()->where(function ($query) use ($searchText) {
            if ($searchText) {
                $query->where(function ($query) use ($searchText) {
                    $query->where('id', intval($searchText))->whereOr('name', 'like', "%{$searchText}%");
                });
            }
        })->order('status')->order('id', 'desc')->paginate($pageSize);

        return EsUtils::stdMessage(true, '', $data);
    }

    /**
     * 显示指定的资源
     * @param int $id 主键编号
     */
    static public function doRead($id)
    {
        if (!empty($id) && !is_numeric($id)) {
            return EsUtils::stdMessage(false, '参数无效', $id);
        }
        $id = intval($id);
        if ($id > 0) {
            $model = self::find($id);
            if (!$model) {
                return EsUtils::stdMessage(false, '记录不存在');
            }
        } else {
            $model = new self();
            $model->status = 1;
        }
        $data = [
            'data' => $model,
            'gender_data' => $model->gender_data,
            'status_data' => $model->status_data,
        ];
        return EsUtils::stdMessage(true, $id, $data);
    }

    /**
     * 保存新建的资源
     * @param array $data 表单数据
     */
    static public function doSave($data, $ip)
    {
        $data['register_ip'] = $ip;
        $data['salt'] = Str::random(8);
        $data['password'] = EsUtils::hashPassword($data['password'], $data['salt']);
        try {
            validate(AuthAdminsValidate::class)->scene('save')->check($data);
        } catch (ValidateException $ex) {
            // 验证失败 输出错误信息
            return EsUtils::stdMessage(false, $ex->getError());
        }
        try {
            // 使用模型静态新增记录的方法，自动过滤客户端传入非法字段并校验数据类型。
            $model = self::create($data);
            $id = $model->id;
            // [反例] 不要使用以下创建记录的方式，这种方式不会自动过滤非法字段。
            // $id = Db::table(self::TABLE_NAME)->insertGetId($data);
            return EsUtils::stdMessage(true, '', $id);
        } catch (PDOException $ex) {
            return EsUtils::stdMessage(false, $ex->getMessage());
        }
    }

    /**
     * 保存更新的资源
     * @param int $id 主键编号
     * @param array $data 表单数据
     * @param string $mode 特殊模式的更新操作，例如 copy, update_one
     */
    static public function doUpdate($id, $data)
    {
        $mode = '';
        if (isset($data['_mode'])) {
            $mode = $data['_mode'];
            unset($data['_mode']);
        }
        // 校验表单参数
        try {
            validate(AuthAdminsValidate::class)->scene($mode)->check($data);
        } catch (ValidateException $ex) {
            // 验证失败 输出错误信息
            return EsUtils::stdMessage(false, $ex->getError());
        }
        // 特殊模式的更新操作
        switch ($mode) {
            case 'copy':
                // 复制指定的资源
                try {
                    $affected = self::copy($id);
                    return EsUtils::stdMessage(true, '', $affected);
                } catch (\Exception $ex) {
                    return EsUtils::stdMessage(false, $ex->getMessage());
                }
            case 'password':
                // 更新密码
                $data['salt'] = Str::random(8);
                $data['password'] = EsUtils::hashPassword($data['new_password'], $data['salt']);
                $data = EsUtils::arrayAllow($data, ['password', 'salt']);
                $data = ['password' => $data['password'], 'salt' => $data['salt']];
                break;
            case 'avatar':
                // 更新头像
                $data = ['avatar' => $data['avatar']];
                break;
            default:
                // 普通更新
                $data = EsUtils::arrayExcept($data, ['created_at', 'updated_at']);

                break;
        }
        // 更新到数据库
        try {
            // 使用模型静态更新记录的方法，自动过滤客户端传入非法字段。
            $affected = self::update($data);
            // [反例] 不要使用以下更新记录的方式，这种方式不会自动过滤非法字段。
            // $affected = self::where('id', $id)->update($data);
            return EsUtils::stdMessage(true, '', $affected);
        } catch (PDOException $ex) {
            return EsUtils::stdMessage(false, $ex->getMessage());
        }
    }

    /**
     * 删除指定的资源
     * @param int $id 主键编号
     */
    static function doDelete($id)
    {
        try {
            $affected = self::destroy($id);
            return EsUtils::stdMessage(true, '', $affected);
        } catch (PDOException $ex) {
            return EsUtils::stdMessage(false, $ex->getMessage());
        }
    }
}
